package kryptoBlatt2;

//Stop and go generator, Variante 1, diese wurde in der Main-Klasse verwendet
public class StopAndGoGeneratorVar1 {

	private LSR lsr1;
	private LSR lsr2;
	private LSR lsr3;
	private String outputHistory;
	private String currentOutput;
	private int periode;
	private int steps;

	
	//In dieser Version wird der SAGG mit jedem Schritt geaendert. Der Zustand der LSR's wird also dauerhaft veraendert wenn man
	//ein Taktsignal anlegt. Will man den Output zum Zeitpunkt t = x, wenn bereits ein t > x erreicht wurde, so
	//muss man entweder einen neuen SAGG verwenden oder den laufenden resetten (resetSAGG())
	//Diese Variante ist effizienter und somit besser, muss jedoch richtig bedient werden
	public StopAndGoGeneratorVar1(LSR lsr1, LSR lsr2, LSR lsr3) {
		this.lsr1 = lsr1;
		this.lsr2 = lsr2;
		this.lsr3 = lsr3;
		initVars();
	}

	//Variablen initialisieren
	private void initVars() {
		this.outputHistory = "";
		this.currentOutput = "0";
		this.periode = 0;
		this.steps = 0;
	}

	//XOR Funktion
	private int xor(int x1, int x2){
		return mod(x1 + x2, 2);
	}

	//Modulo Funktion
	private int mod(int val, int mod){
		int acc = val;
		while(acc < 0){
			acc += mod;
		}
		while(acc >= mod){
			acc -= mod;
		}
		return acc;
	}

	//"Steps" Takte anlegen
	public void step(int steps){
		for (int i = 0; i < steps; i++) {
			shift();
			if(checkIfPeriode(lsr1, lsr2, lsr3)) this.periode = i;
		}
	}

	//Einen einzigen Takt ausfuehren
	public void shift(){
		this.currentOutput = "";
		int output1 = Integer.parseInt(lsr1.getCurrentOutput());
		int output2 = Integer.parseInt(lsr2.getCurrentOutput());
		int output3 = Integer.parseInt(lsr3.getCurrentOutput());
		String out = "";
		lsr1.shift(1);
		output1 = Integer.parseInt(lsr1.getCurrentOutput());
		if(output1 == 1){
			lsr2.shift(1);
			output2 = Integer.parseInt(lsr2.getCurrentOutput());
		}
		else{
			lsr3.shift(1);
			output3 = Integer.parseInt(lsr3.getCurrentOutput());
		}
		out = xor(output2, output3) + "";
		this.currentOutput = out;
		this.outputHistory += out;
		this.steps++;
	}

	//Periode bestimmen, Beim SAGG ist die Periode diejenige Anzahl von Schritten, die noetig ist bis
	//sich wieder alle LSR's (gleichzeitig) im Startzustand befinden
	public int calcPeriode(){
		for (int i = this.steps; this.periode == 0; i++) {
			step(1);
			if(checkIfPeriode(lsr1, lsr2, lsr3)) this.periode = i;
		}
		return getPeriode();
	}

	//Periode ausgeben
	public int getPeriode() {
		return this.periode;
	}

	//Abfrage ob Periode erreicht ist, also alle LSR's wieder im Startzustand sind
	private boolean checkIfPeriode(LSR lsr1, LSR lsr2, LSR lsr3){
		return lsr1.checkIfPeriode() && lsr2.checkIfPeriode() && lsr3.checkIfPeriode();
	}
	
	//Stop and go generator zuruecksetzen
	public void resetSAGG(){
		this.lsr1.resetLSR();
		this.lsr2.resetLSR();
		this.lsr3.resetLSR();
		initVars();
	}

	//Ausgabefolge ausgeben
	public void printOutputHistory(){
		System.out.println(this.outputHistory);
	}

	//Ausgabe des aktuellen Zustands ausgeben
	public void printCurrentOutput(){
		System.out.println(this.currentOutput);
	}
}
